import Matrix2D from "./Matrix2D";
import Math2D from "./Math2D";
import Vector2 from "./Vector2";

export default class MatrixStack {
    // 持有一个矩阵堆栈
    private _mats: Matrix2D[];
    public constructor() {
        // 初始化矩阵堆栈后push一个单位矩阵
        this._mats = [];
        this._mats.push(new Matrix2D());
    }
    // 获取栈顶的矩阵（也就是当前操作矩阵）
    // 矩阵堆栈操作的都是当前堆栈顶部的矩阵
    public get matrix(): Matrix2D {
        if (this._mats.length === 0) {
            alert('矩阵堆栈为空');
            throw new Error('矩阵堆栈为空');
        }
        return this._mats[this._mats.length - 1];
    }
    // 复制栈顶的矩阵，将其push到堆栈中成为当前操作矩阵
    public pushMatrix(): void {
        let mat: Matrix2D = Matrix2D.copy(this.matrix);
        this._mats.push(mat);
    }
    // 删除栈顶的矩阵
    public popMatrix(): void {
        if (this._mats.length === 0) {
            alert('矩阵堆栈为空');
            return;
        }
        this._mats.pop();
    }
    // 将堆栈顶部的矩阵设置为单位矩阵
    public loadIdentity(): void {
        this.matrix.indentity();
    }
    // 将参数mat矩阵替换堆栈顶部的矩阵
    public loadMatrix(mat: Matrix2D): void {
        Matrix2D.copy(mat, this.matrix);
    }
    // 将栈顶(当前矩阵)矩阵与参数矩阵相乘
    // 其作用是更新栈顶元素,累积变换效果
    // 是一个关键操作
    public multMatrix(mat: Matrix2D): void {
        Matrix2D.multiply(this.matrix, mat, this.matrix);
    }
    public translate(x: number = 0, y: number = 0): void {
        let mat: Matrix2D = Matrix2D.makeTranslation(x, y);
        // 看到translate\rotate和scale都会调用multMatrix方法
        this.multMatrix(mat);
    }
    public rotate(angle: number = 0, isRadian: boolean = true): void {
        if (isRadian === false) {
            angle = Math2D.toRadian(angle);
        }
        let mat: Matrix2D = Matrix2D.makeRotation(angle);
        this.multMatrix(mat);
    }
    // 从两个向量构建旋转矩阵
    public rotateFrom(v1: Vector2, v2: Vector2, norm: boolean = false): void {
        let mat: Matrix2D = Matrix2D.makeRotationFromVectors(v1, v2, norm);
        this.multMatrix(mat);
    }
    public scale(x: number = 1.0, y: number = 1.0): void {
        let mat: Matrix2D = Matrix2D.makeScale(x, y);
        this.multMatrix(mat);
    }
    public invert(): Matrix2D {
        let ret: Matrix2D = new Matrix2D();
        if (Matrix2D.invert(this.matrix, ret) === false) {
            alert('堆栈顶部矩阵为奇异矩阵,无法求逆');
            throw new Error('堆栈顶部矩阵为奇异矩阵,无法求逆');
        }
        return ret;
    }
}